package com.nettest.service.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.stereotype.Service;

import com.nettest.entity.system.Menu;
import com.nettest.entity.system.Role;
import com.nettest.service.event.RoleChangedEvent;
import com.nettest.service.system.RoleService;
@Service
public class SecutiryMetadataSourceProvider implements ApplicationListener<RoleChangedEvent>{
	private Map<String,List<String>> roleUrlMap ;
	@Autowired
	private RoleService roleService;
	static Logger logger = Logger.getLogger(SecutiryMetadataSourceProvider.class
			.getName());
	// 存储资源和角色的对应关系，key是资源的url，value是可访问此url的角色集合
	private Map<String, Collection<ConfigAttribute>> securityMetadataSource ;
	@PostConstruct
	public void init() {
		try {
			logger.info("开始缓存角色与资源缓存...");
			securityMetadataSource = new HashMap<String, Collection<ConfigAttribute>>();
			List<Role> loadRoles = roleService.queryAllRoleWithMenu();
			// 角色集合
			Collection<ConfigAttribute> configAttributeCollection = null;
			// 角色
			ConfigAttribute ca = null;
			for (Role role : loadRoles) {
				if(roleUrlMap == null) {
					loadRoleUrlMap(loadRoles);
				}
				List<String> urlLists = roleUrlMap.get(role.getRoleName());
				String roleName = role.getRoleName();
				for (String url : urlLists) {
					if (securityMetadataSource.containsKey(url)) {// 如果已包含此url对应的角色集合，则取出它，并更新它
						configAttributeCollection = securityMetadataSource.get(url);
						ca = new SecurityConfig("ROLE_" + roleName);
						configAttributeCollection.add(ca);
					} else {
						// 如果没有此Url对应的角色集合，则新建一个角色集合
						configAttributeCollection = new ArrayList<ConfigAttribute>();
						// 创建一个包含角色的ConfigAttribute
						ca = new SecurityConfig("ROLE_" + roleName);
						// 将ConfigAttribute放入角色集合中
						configAttributeCollection.add(ca);
					}
					// 将url与对应的角色集合放入map中
					securityMetadataSource.put(url, configAttributeCollection);
				}
			}
			
			logger.info("成功缓存角色与资源缓存...");
		} catch (Exception e) {
			logger.error("缓存角色与资源时发生错误，详细错误如下：",e);
		}
	}
	
	protected void loadRoleUrlMap(List<Role> loadRoles) {
		roleUrlMap = new HashMap<String, List<String>>();
		List<String> urls = null;
		for (Role role : loadRoles) {
			Set<Menu> menus = role.getMenus();
			urls = roleUrlMap.get(role.getRoleName());
			if(urls == null) urls = new ArrayList<String>();
			for (Menu menu : menus) {
				String action = menu.getMenuAction();
				if(action != null) {
					urls.add(action);
				}
			}
			roleUrlMap.put(role.getRoleName(), urls);
		}
	}
	
	public Map<String, Collection<ConfigAttribute>> getSecurityMetadataSource() {
		if(securityMetadataSource == null) {
			init();
		}
		return securityMetadataSource;
	}


	public Map<String, List<String>> getRoleUrlMap() {
		return roleUrlMap;
	}


	public void setRoleUrlMap(Map<String, List<String>> roleUrlMap1) {
		roleUrlMap = roleUrlMap1;
	}

	public RoleService getRoleService() {
		return roleService;
	}

	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}

	@Override
	public void onApplicationEvent(RoleChangedEvent event) {
		if(event instanceof RoleChangedEvent) {
			roleUrlMap = null;
			securityMetadataSource = null;
		}
	}
}
